#include "lcd.h"
#include <xc.h>
#include <p18f4550.h>
#define _XTAL_FREQ 48000000

#define lcd_en PORTBbits.RB3
#define lcd_rs PORTBbits.RB2

void lcd_send_cmd(unsigned char buf)
{
    unsigned char t;
    t = buf & 0xF0;
    PORTB = t;
    lcd_rs = 0;
    lcd_en = 1;
    __delay_us(1);
    lcd_en = 0;
    t = (buf << 4) & 0xF0;
    PORTB = t;
    lcd_rs=0;
    lcd_en = 1;
    __delay_us(1);
    lcd_en = 0;
    __delay_us(2293);
}

void init_lcd(void)
{
    TRISB=0x00;
    PORTB=0x00;
    ADCON1=0x0F;    
    __delay_ms(7);

    PORTB=0x30;
    lcd_rs=0;
    lcd_en=1;
    __delay_us(1);
    lcd_en=0;
    __delay_us(2293);

    PORTB=0x30;
    lcd_rs=0;
    lcd_en=1;
    __delay_us(1);
    lcd_en=0;
    __delay_us(2293);

    PORTB=0x30;
    lcd_rs=0;
    lcd_en=1;
    __delay_us(1);
    lcd_en=0;
    __delay_us(2293);

    PORTB=0x20;
    lcd_rs=0;
    lcd_en=1;
    __delay_us(1);
    lcd_en=0;
    __delay_us(2293);

    lcd_send_cmd((unsigned char)0x28); // sets lcd in 4bit, 2line, 5x7 dots
    lcd_send_cmd((unsigned char)0x01); // clears the lcd
    lcd_send_cmd((unsigned char)0x0F); // sets cursor blinking
    lcd_send_cmd((unsigned char)0x80); // sets the ddram address
    __delay_us(2293);
}

void lcd_clear(void)
{
    lcd_send_cmd(0x01); // 0x01 is the hex command to clear the LCD 
}


void lcd_send_char(unsigned char buf)
{
    unsigned char t;
    t = buf & 0xF0;
    PORTB = t;
    lcd_rs = 1;
    lcd_en = 1;
    __delay_us(1);
    lcd_en = 0;
    t = (buf << 4) & 0xF0;
    PORTB = t;
    lcd_rs = 1;
    lcd_en = 1;
    __delay_us(1);
    lcd_en = 0;
    __delay_us(2293);
}

void lcd_send_txt(const unsigned char * p)
{
    while (*p != '\0')
    {
        lcd_send_char(*p);
        p++;
    }
}

void lcd_change_line(void)
{
    lcd_send_cmd(0xC0);
}

void lcd_move_cursor(unsigned int x, unsigned int y)
{
    unsigned char target_address=0x00;
    target_address=x; // x offset is the lower nibble so copying it as it is
    if (y>0) // checking is the line number is not 0
        target_address = 0x40 | target_address; // case: when line number is not 0
    target_address = 0x80 | target_address; // ORing it, 1 in MSB is identified as a move cursor command and rest 7 bits are address of target location refer device datasheet for more details
    lcd_send_cmd(target_address);
}
void lcd_send_char_xy(unsigned int x, unsigned int y, unsigned char s )
{
    lcd_move_cursor(x,y); // moving cursor to the required position
    lcd_send_char(s); // sending data to print
}

void lcd_send_txt_xy(unsigned int x, unsigned int y, unsigned char *p )
{
    lcd_move_cursor(x,y); // moving cursor to the required position
    lcd_send_txt(p); // sending data to print
}
